﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Linq.Expressions;
using DailyPoetryX.Models;
using DailyPoetryX.Services;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;

namespace DailyPoetryX.ViewModels {
    public class QueryPageViewModel : ViewModelBase {
        /******** 构造函数 ********/

        IContentNavigationService contentNavigationService;

        public QueryPageViewModel(
            IContentNavigationService contentNavigationService) {
            this.contentNavigationService = contentNavigationService;
            Filters.Add(new FilterViewModel(this));
        }

        /******** 绑定属性 ********/

        public ObservableCollection<FilterViewModel> Filters { get; } =
            new ObservableCollection<FilterViewModel>();

        public PoetryQuery PoetryQuery {
            get => _poetryQuery;
            set => Set(nameof(PoetryQuery), ref _poetryQuery, value);
        }

        private PoetryQuery _poetryQuery;

        /******** 绑定命令 ********/

        public RelayCommand AddCommand => _addCommand ?? (_addCommand =
            new RelayCommand(() => Filters.Add(new FilterViewModel(this))));

        private RelayCommand _addCommand;

        public RelayCommand QueryCommand =>
            _queryCommand ?? (_queryCommand = new RelayCommand(async () => {
                var parameter = Expression.Parameter(typeof(Poetry), "p");
                var trueExpression = Expression.MakeBinary(
                    ExpressionType.AndAlso, Expression.Constant(true),
                    Expression.Constant(true));
                var aggregatedExpression = Filters
                    .Where(p => !string.IsNullOrWhiteSpace(p.Content))
                    .Select(p => GetExpression(parameter, p))
                    .Aggregate(trueExpression, Expression.AndAlso);
                var where =
                    Expression.Lambda<Func<Poetry, bool>>(aggregatedExpression,
                        parameter);
                await contentNavigationService.NavigateToAsync(
                    ContentNavigationServiceConstants.ResultPage, where);
            }));

        private RelayCommand _queryCommand;

        public RelayCommand PageAppearingCommand =>
            _pageAppearingCommand ?? (_pageAppearingCommand = new RelayCommand(
                () => {
                    if (PoetryQuery == null) return;

                    Filters.Clear();
                    Filters.Add(new FilterViewModel(this) {
                        Type = FilterType.NameFilter, Content = PoetryQuery.Name
                    });
                    Filters.Add(new FilterViewModel(this) {
                        Type = FilterType.AuthorNameFilter,
                        Content = PoetryQuery.AuthorName
                    });
                    PoetryQuery = null;
                }));

        private RelayCommand _pageAppearingCommand;

        /******** 公开方法 ********/

        public void AddFilter(FilterViewModel filterViewModel) =>
            Filters.Insert(Filters.IndexOf(filterViewModel) + 1,
                new FilterViewModel(this));

        public void RemoveFilter(FilterViewModel filterViewModel) {
            Filters.Remove(filterViewModel);
            if (Filters.Count == 0) {
                Filters.Add(new FilterViewModel(this));
            }
        }

        /******** 私有方法 ********/

        private static Expression GetExpression(ParameterExpression parameter,
            FilterViewModel filterViewModel) {
            var property = Expression.Property(parameter,
                filterViewModel.Type.PropertyName);
            var method =
                typeof(string).GetMethod("Contains", new[] {typeof(string)});
            var condition =
                Expression.Constant(filterViewModel.Content, typeof(string));
            return Expression.Call(property, method, condition);
        }
    }

    public class FilterViewModel : ViewModelBase {
        /******** 构造函数 ********/

        private QueryPageViewModel queryPageViewModel;

        public FilterViewModel(QueryPageViewModel queryPageViewModel) {
            this.queryPageViewModel = queryPageViewModel;
        }

        /******** 绑定属性 ********/

        public FilterType Type {
            get => _type;
            set => Set(nameof(Type), ref _type, value);
        }

        private FilterType _type = FilterType.NameFilter;

        public string Content {
            get => _content;
            set => Set(nameof(Content), ref _content, value);
        }

        private string _content;

        /******** 绑定命令 ********/

        public RelayCommand AddCommand => _addCommand ?? (_addCommand =
            new RelayCommand(() => queryPageViewModel.AddFilter(this)));

        private RelayCommand _addCommand;

        public RelayCommand RemoveCommand =>
            _removeCommand ?? (_removeCommand =
                new RelayCommand(() => queryPageViewModel.RemoveFilter(this)));

        private RelayCommand _removeCommand;
    }

    public class FilterType {
        private static Poetry _forName = new Poetry();

        public static readonly FilterType NameFilter =
            new FilterType("标题", nameof(_forName.Name));

        public static readonly FilterType AuthorNameFilter =
            new FilterType("作者", nameof(_forName.AuthorName));

        public static readonly FilterType ContentFilter =
            new FilterType("内容", nameof(_forName.Content));

        public static List<FilterType> FilterTypes { get; } =
            new List<FilterType> {NameFilter, AuthorNameFilter, ContentFilter};

        private FilterType(string name, string propertyName) {
            Name = name;
            PropertyName = propertyName;
        }

        public string Name { get; }

        public string PropertyName { get; }
    }
}